Micron Document
--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
| SparkN0de-git | SparkN0de |
--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------

Node / ReticulumProjects / MeshChatX.git / files / meshchatx / src / frontend / js / networkStartupWait.js

Displaying Raw • Download


meshchatx/src/frontend/js/networkStartupWait.js ec74a2651e897325b14269ae52d11b1e12f0b6e2 (ec74a265) Text, 5.71 KB

T8b949e// SPDX-License-Identifier: 0BSD AND MIT

Tff7b72export Tff7b72const Te6edf3STARTUP_STAGE_LABELS Tff7b72= Tb4b4b4{
Te6edf3httpTff7b72: Ta5d6ff"Getting things ready…"Tb4b4b4,
Te6edf3startingTff7b72: Ta5d6ff"Getting the mesh ready…"Tb4b4b4,
Te6edf3rnsTff7b72: Ta5d6ff"Connecting to the mesh…"Tb4b4b4,
Te6edf3identityTff7b72: Ta5d6ff"Almost there…"Tb4b4b4,
Te6edf3readyTff7b72: Ta5d6ff"Ready"Tb4b4b4,
Te6edf3failedTff7b72: Ta5d6ff"Startup failed"Tb4b4b4,
Tb4b4b4}Tb4b4b4;

T8b949e/**
* Interpret a /api/v1/status JSON body for boot gating.
* Only own properties are trusted so prototype pollution cannot spoof readiness.
* @param {unknown} data
* @returns {{ kind: "ready" | "ui" | "degraded" | "failed" | "starting" | "invalid", stage?: string, error?: string, label?: string }}
*/
Tff7b72export Tff7b72function Te6edf3interpretStartupStatusTb4b4b4(Te6edf3dataTb4b4b4) Tb4b4b4{
Tff7b72if Tb4b4b4(Tff7b72!Te6edf3data Tff7b72|| Tff7b72typeof Te6edf3data Tff7b72!== Ta5d6ff"object" Tff7b72|| Tffa657ArrayTb4b4b4.Te6edf3isArrayTb4b4b4(Te6edf3dataTb4b4b4)Tb4b4b4) Tb4b4b4{
Tff7b72return Tb4b4b4{ Te6edf3kindTff7b72: Ta5d6ff"invalid" Tb4b4b4}Tb4b4b4;
Tb4b4b4}
Tff7b72const Te6edf3own Tff7b72= Tb4b4b4(Te6edf3keyTb4b4b4) Tb4b4b4=> Tffa657ObjectTb4b4b4.Te6edf3prototypeTb4b4b4.Te6edf3hasOwnPropertyTb4b4b4.Te6edf3callTb4b4b4(Te6edf3dataTb4b4b4, Te6edf3keyTb4b4b4)Tb4b4b4;
Tff7b72const Te6edf3status Tff7b72= Te6edf3ownTb4b4b4(Ta5d6ff"status"Tb4b4b4) Tff7b72? Te6edf3dataTb4b4b4.Te6edf3status Tff7b72: Tff7b72undefinedTb4b4b4;
Tff7b72const Te6edf3stage Tff7b72= Te6edf3ownTb4b4b4(Ta5d6ff"stage"Tb4b4b4) Tff7b72&& Tff7b72typeof Te6edf3dataTb4b4b4.Te6edf3stage Tff7b72=== Ta5d6ff"string" Tff7b72? Te6edf3dataTb4b4b4.Te6edf3stage Tff7b72: Tff7b72undefinedTb4b4b4;
Tff7b72const Te6edf3networkReady Tff7b72= Te6edf3ownTb4b4b4(Ta5d6ff"network_ready"Tb4b4b4) Tff7b72&& Te6edf3dataTb4b4b4.Te6edf3network_ready Tff7b72=== Tff7b72trueTb4b4b4;
Tff7b72const Te6edf3uiReady Tff7b72= Te6edf3ownTb4b4b4(Ta5d6ff"ui_ready"Tb4b4b4) Tff7b72&& Te6edf3dataTb4b4b4.Te6edf3ui_ready Tff7b72=== Tff7b72trueTb4b4b4;
Tff7b72const Te6edf3networkDegraded Tff7b72= Te6edf3ownTb4b4b4(Ta5d6ff"network_degraded"Tb4b4b4) Tff7b72&& Te6edf3dataTb4b4b4.Te6edf3network_degraded Tff7b72=== Tff7b72trueTb4b4b4;
Tff7b72const Te6edf3error Tff7b72= Te6edf3ownTb4b4b4(Ta5d6ff"error"Tb4b4b4) Tff7b72&& Tff7b72typeof Te6edf3dataTb4b4b4.Te6edf3error Tff7b72=== Ta5d6ff"string" Tff7b72? Te6edf3dataTb4b4b4.Te6edf3error Tff7b72: Tff7b72undefinedTb4b4b4;

Tff7b72if Tb4b4b4(Te6edf3status Tff7b72=== Ta5d6ff"failed"Tb4b4b4) Tb4b4b4{
T8b949e// HTTP is up and the backend marked UI as usable: mount the app in
T8b949e// degraded mode so interfaces/settings remain reachable for recovery.
Tff7b72if Tb4b4b4(Te6edf3uiReady Tff7b72|| Te6edf3networkDegradedTb4b4b4) Tb4b4b4{
Tff7b72return Tb4b4b4{
Te6edf3kindTff7b72: Ta5d6ff"degraded"Tb4b4b4,
Te6edf3stageTff7b72: Te6edf3stage Tff7b72|| Ta5d6ff"failed"Tb4b4b4,
Te6edf3errorTb4b4b4,
Tb4b4b4}Tb4b4b4;
Tb4b4b4}
Tff7b72return Tb4b4b4{
Te6edf3kindTff7b72: Ta5d6ff"failed"Tb4b4b4,
Te6edf3stageTff7b72: Te6edf3stage Tff7b72|| Ta5d6ff"failed"Tb4b4b4,
Te6edf3errorTb4b4b4,
Tb4b4b4}Tb4b4b4;
Tb4b4b4}
Tff7b72if Tb4b4b4(Te6edf3status Tff7b72=== Ta5d6ff"ok" Tff7b72|| Te6edf3networkReadyTb4b4b4) Tb4b4b4{
Tff7b72return Tb4b4b4{ Te6edf3kindTff7b72: Ta5d6ff"ready"Tb4b4b4, Te6edf3stageTff7b72: Te6edf3stage Tff7b72|| Ta5d6ff"ready" Tb4b4b4}Tb4b4b4;
Tb4b4b4}
Tff7b72if Tb4b4b4(Te6edf3status Tff7b72=== Ta5d6ff"starting" Tff7b72|| Te6edf3status Tff7b72=== Tff7b72undefinedTb4b4b4) Tb4b4b4{
Tff7b72const Te6edf3resolvedStage Tff7b72= Te6edf3stage Tff7b72|| Ta5d6ff"starting"Tb4b4b4;
Tff7b72const Te6edf3label Tff7b72= Te6edf3STARTUP_STAGE_LABELSTb4b4b4[Te6edf3resolvedStageTb4b4b4] Tff7b72|| Ta5d6ff"Starting network…"Tb4b4b4;
T8b949e// HTTP is bound and the shell may mount while RNS/identity finish.
Tff7b72if Tb4b4b4(Te6edf3uiReadyTb4b4b4) Tb4b4b4{
Tff7b72return Tb4b4b4{
Te6edf3kindTff7b72: Ta5d6ff"ui"Tb4b4b4,
Te6edf3stageTff7b72: Te6edf3resolvedStageTb4b4b4,
Te6edf3labelTb4b4b4,
Tb4b4b4}Tb4b4b4;
Tb4b4b4}
Tff7b72return Tb4b4b4{
Te6edf3kindTff7b72: Ta5d6ff"starting"Tb4b4b4,
Te6edf3stageTff7b72: Te6edf3resolvedStageTb4b4b4,
Te6edf3labelTb4b4b4,
Tb4b4b4}Tb4b4b4;
Tb4b4b4}
Tff7b72return Tb4b4b4{ Te6edf3kindTff7b72: Ta5d6ff"invalid"Tb4b4b4, Te6edf3stage Tb4b4b4}Tb4b4b4;
Tb4b4b4}

T8b949e/**
* Poll /api/v1/status until the UI may mount (ui_ready), mesh is ready, or degraded.
* @param {{
* fetchImpl?: typeof fetch,
* now?: () => number,
* sleep?: (ms: number) => Promise<void>,
* timeoutMs?: number,
* onLine?: (text: string) => void,
* onErrorState?: () => void,
* onDegraded?: (error?: string) => void,
* statusUrl?: string,
* mountOnUiReady?: boolean,
* }} [options]
* @returns {Promise<"ready" | "ui" | "degraded" | false>}
*/
Tff7b72export Tff7b72async Tff7b72function Te6edf3waitForNetworkReadyTb4b4b4(Te6edf3options Tff7b72= Tb4b4b4{Tb4b4b4}Tb4b4b4) Tb4b4b4{
Tff7b72const Te6edf3fetchImpl Tff7b72= Te6edf3optionsTb4b4b4.Te6edf3fetchImpl Tff7b72|| Te6edf3fetchTb4b4b4;
Tff7b72const Te6edf3now Tff7b72= Te6edf3optionsTb4b4b4.Te6edf3now Tff7b72|| Tffa657DateTb4b4b4.Te6edf3nowTb4b4b4;
Tff7b72const Te6edf3sleep Tff7b72= Te6edf3optionsTb4b4b4.Te6edf3sleep Tff7b72|| Tb4b4b4(Tb4b4b4(Te6edf3msTb4b4b4) Tb4b4b4=> Tff7b72new Tffa657PromiseTb4b4b4(Tb4b4b4(Te6edf3resolveTb4b4b4) Tb4b4b4=> Te6edf3setTimeoutTb4b4b4(Te6edf3resolveTb4b4b4, Te6edf3msTb4b4b4)Tb4b4b4)Tb4b4b4)Tb4b4b4;
Tff7b72const Te6edf3timeoutMs Tff7b72= Te6edf3optionsTb4b4b4.Te6edf3timeoutMs Tff7b72?? T79c0ff120000Tb4b4b4;
Tff7b72const Te6edf3onLine Tff7b72= Te6edf3optionsTb4b4b4.Te6edf3onLine Tff7b72|| Tb4b4b4(Tb4b4b4(Tb4b4b4) Tb4b4b4=> Tb4b4b4{Tb4b4b4}Tb4b4b4)Tb4b4b4;
Tff7b72const Te6edf3onErrorState Tff7b72= Te6edf3optionsTb4b4b4.Te6edf3onErrorState Tff7b72|| Tb4b4b4(Tb4b4b4(Tb4b4b4) Tb4b4b4=> Tb4b4b4{Tb4b4b4}Tb4b4b4)Tb4b4b4;
Tff7b72const Te6edf3onDegraded Tff7b72= Te6edf3optionsTb4b4b4.Te6edf3onDegraded Tff7b72|| Tb4b4b4(Tb4b4b4(Tb4b4b4) Tb4b4b4=> Tb4b4b4{Tb4b4b4}Tb4b4b4)Tb4b4b4;
Tff7b72const Te6edf3statusUrl Tff7b72= Te6edf3optionsTb4b4b4.Te6edf3statusUrl Tff7b72|| Ta5d6ff"/api/v1/status"Tb4b4b4;
Tff7b72const Te6edf3mountOnUiReady Tff7b72= Te6edf3optionsTb4b4b4.Te6edf3mountOnUiReady Tff7b72!== Tff7b72falseTb4b4b4;

Tff7b72const Te6edf3deadline Tff7b72= Te6edf3nowTb4b4b4(Tb4b4b4) Tff7b72+ Te6edf3timeoutMsTb4b4b4;
Tff7b72let Te6edf3delayMs Tff7b72= T79c0ff200Tb4b4b4;
Tff7b72while Tb4b4b4(Te6edf3nowTb4b4b4(Tb4b4b4) Tff7b72< Te6edf3deadlineTb4b4b4) Tb4b4b4{
Tff7b72try Tb4b4b4{
Tff7b72const Te6edf3response Tff7b72= Tff7b72await Te6edf3fetchImplTb4b4b4(Te6edf3statusUrlTb4b4b4, Tb4b4b4{ Te6edf3cacheTff7b72: Ta5d6ff"no-store" Tb4b4b4}Tb4b4b4)Tb4b4b4;
Tff7b72if Tb4b4b4(Te6edf3responseTb4b4b4.Te6edf3okTb4b4b4) Tb4b4b4{
Tff7b72const Te6edf3data Tff7b72= Tff7b72await Te6edf3responseTb4b4b4.Te6edf3jsonTb4b4b4(Tb4b4b4)Tb4b4b4;
Tff7b72const Te6edf3interpreted Tff7b72= Te6edf3interpretStartupStatusTb4b4b4(Te6edf3dataTb4b4b4)Tb4b4b4;
Tff7b72if Tb4b4b4(Te6edf3interpretedTb4b4b4.Te6edf3kind Tff7b72=== Ta5d6ff"degraded"Tb4b4b4) Tb4b4b4{
Te6edf3onLineTb4b4b4(Te6edf3interpretedTb4b4b4.Te6edf3error Tff7b72|| Ta5d6ff"Mesh network unavailable. Opening recovery UI…"Tb4b4b4)Tb4b4b4;
Te6edf3onDegradedTb4b4b4(Te6edf3interpretedTb4b4b4.Te6edf3errorTb4b4b4)Tb4b4b4;
Tff7b72return Ta5d6ff"degraded"Tb4b4b4;
Tb4b4b4}
Tff7b72if Tb4b4b4(Te6edf3interpretedTb4b4b4.Te6edf3kind Tff7b72=== Ta5d6ff"failed"Tb4b4b4) Tb4b4b4{
Te6edf3onLineTb4b4b4(Te6edf3interpretedTb4b4b4.Te6edf3error Tff7b72|| Ta5d6ff"Network startup failed."Tb4b4b4)Tb4b4b4;
Te6edf3onErrorStateTb4b4b4(Tb4b4b4)Tb4b4b4;
Tff7b72return Tff7b72falseTb4b4b4;
Tb4b4b4}
Tff7b72if Tb4b4b4(Te6edf3interpretedTb4b4b4.Te6edf3kind Tff7b72=== Ta5d6ff"ready"Tb4b4b4) Tb4b4b4{
Tff7b72return Ta5d6ff"ready"Tb4b4b4;
Tb4b4b4}
Tff7b72if Tb4b4b4(Te6edf3interpretedTb4b4b4.Te6edf3kind Tff7b72=== Ta5d6ff"ui" Tff7b72&& Te6edf3mountOnUiReadyTb4b4b4) Tb4b4b4{
Te6edf3onLineTb4b4b4(Te6edf3interpretedTb4b4b4.Te6edf3label Tff7b72|| Ta5d6ff"Opening the app…"Tb4b4b4)Tb4b4b4;
Tff7b72return Ta5d6ff"ui"Tb4b4b4;
Tb4b4b4}
Tff7b72if Tb4b4b4(Te6edf3interpretedTb4b4b4.Te6edf3kind Tff7b72=== Ta5d6ff"starting" Tff7b72|| Te6edf3interpretedTb4b4b4.Te6edf3kind Tff7b72=== Ta5d6ff"ui"Tb4b4b4) Tb4b4b4{
Te6edf3onLineTb4b4b4(Te6edf3interpretedTb4b4b4.Te6edf3label Tff7b72|| Ta5d6ff"Getting things ready…"Tb4b4b4)Tb4b4b4;
Tb4b4b4}
Tb4b4b4}
Tb4b4b4} Tff7b72catch Tb4b4b4{
Te6edf3onLineTb4b4b4(Ta5d6ff"Still starting…"Tb4b4b4)Tb4b4b4;
Tb4b4b4}
Tff7b72await Te6edf3sleepTb4b4b4(Te6edf3delayMsTb4b4b4)Tb4b4b4;
Te6edf3delayMs Tff7b72= Tffa657MathTb4b4b4.Te6edf3minTb4b4b4(Te6edf3delayMs Tff7b72+ T79c0ff100Tb4b4b4, T79c0ff1000Tb4b4b4)Tb4b4b4;
Tb4b4b4}
Te6edf3onLineTb4b4b4(Ta5d6ff"Network startup timed out. Try reloading."Tb4b4b4)Tb4b4b4;
Te6edf3onErrorStateTb4b4b4(Tb4b4b4)Tb4b4b4;
Tff7b72return Tff7b72falseTb4b4b4;
Tb4b4b4}

T8b949e/**
* Continue polling until mesh network_ready or degraded/failed.
* Used after an early UI mount on ui_ready.
* @param {{
* fetchImpl?: typeof fetch,
* now?: () => number,
* sleep?: (ms: number) => Promise<void>,
* timeoutMs?: number,
* onLine?: (text: string) => void,
* onErrorState?: () => void,
* onDegraded?: (error?: string) => void,
* statusUrl?: string,
* }} [options]
* @returns {Promise<"ready" | "degraded" | false>}
*/
Tff7b72export Tff7b72async Tff7b72function Te6edf3waitForMeshReadyTb4b4b4(Te6edf3options Tff7b72= Tb4b4b4{Tb4b4b4}Tb4b4b4) Tb4b4b4{
Tff7b72return Te6edf3waitForNetworkReadyTb4b4b4(Tb4b4b4{
Tb4b4b4...Te6edf3optionsTb4b4b4,
Te6edf3mountOnUiReadyTff7b72: Tff7b72falseTb4b4b4,
Tb4b4b4}Tb4b4b4)Tb4b4b4;
Tb4b4b4}


──────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────